<?php

// 导入第三方httpclient工具。用于向拍拍发送post请求
Yii::import('application.vendors.*');
require_once('httpclient/HttpClient.class.php');

/*
 * API处理控制器。
 * @Author dan.shen
 */
class TempController extends CController
{
 
    /**
	 * 默认操作
	 */
	public $defaultAction='';
	
	/**
	 * @return array action filters
	 */
	public function filters()
	{
		return array(
			'accessControl', // perform access control for CRUD operations
		);
	}

	/**
	 * TODO: 加权限控制
	 */
	public function accessRules()
	{
		return array(
			array('allow',
				'users'=>array('*'),
			),
		);
	}
	
	public function actionTest()
	{
	    //$data = $_POST['CALL'];
	    //$params = json_decode($data,true);
	    
		$apiConfig = Yii::app()->params['paipaiApi'];
	    $xml = simplexml_load_file(Yii::app()->basePath."/resources/api/getmetaclasses.xml");
	    $this->_buildHead($xml->head);
	    
	    /*
		 * 在此装配xml的body。
		 */ 
	    $array = include(Yii::app()->basePath.'/config/paipaiApi.php');
	    
	    $params = json_decode('{
								"page":{
								    "pagesize":20,
								    "pageindex":1,
								    "pagetotal":0
	                             }
								}',true);
	    
	    $this->_buildAPIBody($xml->body,$array['getdeal'],$params); 
	    // 计算签名值
	    $xml->sign = $this->_generateSign($xml);
	    //debug
	    //echo $xml->asXML();
	    
	    //echo HttpClient::quickPost(Yii::app()->params['paipaiApi']['url']['getdeal'],array('CALL'=>$xml->asXML()));
	    $response = HttpClient::quickPost("http://rest.paipai.com/brand_metaclass/getall",array('CALL'=>$xml->asXML()));
	    
	    $resultXml = simplexml_load_string($response);
	    
	    ppMetaClass::model()->deleteAll();
	    
	    $infolist = $resultXml->body->metaclassinfolist->metaclassinfo;
	    
	    foreach ($infolist as $info)
	    {
	        $metaclass = new ppMetaClass;
	        $metaclass->name = $info->metaclassname;
	        $metaclass->metaId = $info->metaclassid;
	        $metaclass->description = $info->metaclassdesc;
	        
	        $metaclass->save();
	    }
	    
	    $pageTotal = $resultXml->body->page->pagetotal;
	    $xml->body->page->pagetotal = $pageTotal;
	    
	    for($index = 2; $index <= $pageTotal; $index++)
	    {
	        $xml->body->page->pageindex = $index;
	        $xml->sign = $this->_generateSign($xml);
	        $resp= HttpClient::quickPost("http://rest.paipai.com/brand_metaclass/getall",array('CALL'=>$xml->asXML()));
	        $result = simplexml_load_string($resp);
	        
		    $infos= $result->body->metaclassinfolist->metaclassinfo;
		    
		    foreach ($infos as $info)
		    {
		        $metaclass = new ppMetaClass;
		        $metaclass->name = $info->metaclassname;
		        $metaclass->metaId = $info->metaclassid;
		        $metaclass->description = $info->metaclassdesc;
		        
		        $metaclass->save();
		    }
	    }
	    echo "finished";
	    //echo $response;
//	    $xml = new DOMDocument;
//	    $xml->loadXML($response);
//		
//		$xsl = new DOMDocument;
//		$xsl->load(Yii::app()->basePath."/resources/xsl/metaclasses.xsl");
//		
//		$proc = new XSLTProcessor;
//		$proc->importStyleSheet($xsl); // attach the xsl rules
//		
//		echo $proc->transformToXML($xml);
	}
	
	public function actionGetAttrs()
	{
	    set_time_limit(1000);
	    $apiConfig = Yii::app()->params['paipaiApi'];
	    $xml = simplexml_load_file(Yii::app()->basePath."/resources/api/getattrclasslist.xml");
	    $this->_buildHead($xml->head);
	    
	    /*
		 * 在此装配xml的body。
		 */ 
	    $array = include(Yii::app()->basePath.'/config/paipaiApi.php');
	    
	    $params = json_decode('{
								"metaclassid":""
								}',true);
	    
	    $this->_buildAPIBody($xml->body,$array['getdeal'],$params); 
	    
	    $metaclasses = ppMetaClass::model()->findAll("id > 949 and id < 1025");
	    
	    //ppBrandAttr::model()->deleteAll();
	    
	    foreach ($metaclasses as $metaclass)
	    {
	        $metaclassid = $metaclass->metaId;
	        $xml->body->metaclassid = $metaclassid;
	        // 计算签名值
	        $xml->sign = $this->_generateSign($xml);
	        
		    //debug
		    //echo $xml->asXML();
		    
		    //echo HttpClient::quickPost(Yii::app()->params['paipaiApi']['url']['getdeal'],array('CALL'=>$xml->asXML()));
		    $response = HttpClient::quickPost("http://rest.paipai.com/brand_attrclass/getattrclasslist",array('CALL'=>$xml->asXML()));
	        $result = simplexml_load_string($response);
	        
	        $infos= $result->body->attrclassinfolist->attrclassinfo;
	        
	        if (isset($infos)) {
		        foreach ($infos as $info)
		        {
		            if ($info->attrclassname == '品牌')
		            {
		                $attroptioninfos = $info->attroptionidlist->attroptioninfo;
		                
		                foreach ($attroptioninfos as $attroptioninfo)
		                {
		                    $ppBrandAttr = new ppBrandAttr;
		                    $ppBrandAttr->attrName = $attroptioninfo->attroptionname;
		                    $ppBrandAttr->attrId = $attroptioninfo->attroptionid;
		                    try{
		                        $ppBrandAttr->save();
		                    } catch (CDbException $cde) {
		                         // 忽略
		                    }
		                    
		                }
		             
		                break;
		            }
		        }
	        }
	        
		   // ppBrandAttr
	    }
	    
	    echo "finished";
	    
	}
	
	
	/**
	 * 因为所有接口的头节点都是用同一组值，此函数用于被所有接口装配头(head)节点的值。
	 * 
	 * @param $headNode api的XML中的头节点（head）
	 */
	protected function _buildHead($headNode)
	{
	    // 装配main.php配置信息中的参数
	    $headConfig = Yii::app()->params['paipaiApi']['head'];
	    foreach ($headConfig as $key=>$value)
	    {
	        $headNode->$key=$value;
	    }
	    
	    //  装配时间和序列号.拍拍有的接口是允许不补零的，有的必须补零。这里统一补零
	    $time = time();
	    $headNode->time = date('Y-m-d H:i:s',$time);
	    $headNode->seqno = $time;
	    
	}
	
	/**
	 * 工具方法，用于过滤XML中的空节点。
	 */
	protected function _filterEmptyNodes($xml)
	{
	    $dom = new DOMDocument();
	    $dom->loadXML($xml);
	    $xpath = new DOMXPath($dom);
	    $entries = $xpath->query(@"//*[not(node())]");
	    foreach ($entries as $entry)
	    {
	        $entry->parentNode->removeChild($entry);
	    }
	    
	    return $dom->saveXML();
	}
	
	/**
	 * 工具方法。采用递归的方式解析从json格式的数据解析来的数组并把此数组转化为XML格式的数据。
	 * 
	 * @param $xmlNode 父节点
	 * @param $apiConfig 配置文件数组，格式为：
     *     'local_code'=>array(
		        'realname'=>'local_code',
		        'valuetype'=>'CDATA',
		    ),
		    其中，realname是标签的真实名字，valuetype是子叶子节点的数据类型。
	 * @param $params 数组结构的json数据的一部分
	 * @param $superKey 上级节点的key值，用来判断叶子文本的类型
	 * @return unknown_type
	 */	
    protected function _buildAPIBody($xmlNode,$apiConfig,$params,$superKey='')
	{
	    foreach ($params as $key=>$param)
	    {
	        /*
	         * 获取此标识符对应的配置信息.配置信息主要有:
	         * 'realname'=>'local_code', // 实际对应的标签名
	         * 'valuetype'=>'CDATA/STRING/BIN', // 如果是叶子节点,则需要获取值的类型.
	         * 如果配置信息不存在，则初始化默认的配置信息。默认的realname为$key的值，默认的valuetype是STRING
	         */ 
	    	$buildInfo = array();
	        if (isset($apiConfig[$key]))
	        {
	        	$buildInfo = $apiConfig[$key];
	        } else {
	        	$buildInfo['realname'] = $key;
	        	$buildInfo['valuetype'] = 'STRING';
	        }
	        
	        
	        if (!is_int($key))
	        {
	            /*
	             * 处理键值是'@attributes'类型的数组.
	             * 这类数组将被作为父节点的属性值创建。
	             */ 
		        if ($key == '@attributes')
		        {
		            foreach ($param as $attrkey=>$attrvalue)
		            {
		                $xmlNode->addAttribute($attrkey,$attrvalue);
		            }
		        } 
		        // json中如果有非"xx:xxx"格式的字符串,则decode出来为空的数组.为了支持该特性,将纯文本的叶子节点关联到"@text"标识符上
	            elseif ($key == '@text')
		        {
		            // 如果是文本,则需要在当前节点上添加文本节点.   
		            if (!isset($apiConfig[$superKey]['valuetype']))
		            {
		                $apiConfig[$superKey]['valuetype'] = 'STRING';
		            }
		            $this->_appendText($xmlNode,$param,$apiConfig[$superKey]['valuetype']);
		        }
		        else{
		            if(!is_array($param))
		            {
		                //如果$param非数组,则说明这是一个简单节点.直接创建并赋值
		                $this->_createNode($xmlNode,$buildInfo['realname'],$param,$buildInfo['valuetype']);
		            }else{
		                /*
		                 * 如果参数不是数组,则参数里的节点可能是列表节点,也可能是子节点.
		                 * 也可能是两者的混合.这里分两种情况分别处理.
		                 * 1. 对于列表节点,它的key值是int类型的.所有的int值都被替换为当前的key值.递归调用_buildAPIBody函数处理
		                 * 2. 对于非列表节点,它的key值是非int类型的.这些节点都是当前节点的子节点.则将它们全部放入一个数组中,循环结束后
		                 *    创建一个当前节点作为父节点,递归调用_buildAPIBody函数继续处理
		                 */ 
		                $subNodes = array();
		                
		                foreach ($param as $itemkey=>$itemvalue)
		                {
		                    if (is_int($itemkey))
		                    {
		                        $array[$key] = $itemvalue;
		                        $this->_buildAPIBody($xmlNode,$apiConfig,$array,$superKey);
		                    } else {
		                        $subNodes[$itemkey] = $itemvalue;
		                    }
		                }
		                
		                if (!empty($subNodes))
		                {
		                    $node = $xmlNode->addChild($buildInfo['realname']);
		                    $this->_buildAPIBody($node,$apiConfig,$subNodes,$key);
		                }
		                
		            }
		            
		        }
	        } 
	        
	        // 如果传进来的key是int值，则不处理
	       
	    }
	}
	
	/**
	 * 工具方法。为$xmlNode节点创建带叶子节点的子节点。
	 * 
	 * 1. $type='CDATA'：创建&lt;![CDATA[...]]&gt;叶子节点
	 * 2. $type='STRING'：直接将文本参数作为文本节点添加
	 * 3. $type='BIN'：二进制文件类型。这种类型现在只支持接收URL形式的参数，读取二进制文件并转化成base64格式字符串输出
	 * 
	 * @param $xmlNode
	 * @param $nodeName
	 * @param $content
	 * @param $type 三种类型：1. CDATA 2. STRING 3. BIN
	 * @return unknown_type
	 */
	protected function _createNode($xmlNode,$nodeName,$content,$type)
	{
	     $node = '';
	     if ($type=='CDATA')
	     {
	         $node = $xmlNode->addChild($nodeName);
		     $domNode = dom_import_simplexml($node);
		     $no = $domNode->ownerDocument;
		     $domNode->appendChild($no->createCDATASection($content));
	     }elseif ($type=='STRING'){
	         $node = $xmlNode->addChild($nodeName,$content);
	     }elseif ($type=='BIN'){
	     	 $data = '';
	         $file = fopen($content,'rb');
			 while (!feof($file)) {
		         $data .= fread($file, 8192);
			 }
			 fclose($file);
			 $data = base64_encode($data);
			 $node = $xmlNode->addChild($nodeName,$data);
	     }
	     
	     return $node;
	}
	
	/**
	 * 工具方法。根据参数"$type"类型为$node节点添加文本节点。
	 * 
	 * 1. $type='CDATA'：创建&lt;![CDATA[...]]&gt;节点
	 * 2. $type='STRING'：直接将文本参数作为文本节点添加
	 * 3. $type='BIN'：二进制文件类型。这种类型现在只支持接收URL形式的参数，读取二进制文件并转化成base64格式字符串输出
	 * 
	 * @param $node
	 * @param $text
	 * @param $type 三种类型：1. CDATA 2. STRING 3. BIN
	 * @return NULL
	 */
	protected function _appendText($node,$text,$type)
	{
	    $domNode = dom_import_simplexml($node);

	    if ($type=='CDATA')
	    {
		    $no = $domNode->ownerDocument;
		    $domNode->appendChild($no->createCDATASection($text));
	    }
	    
	    elseif ($type=='STRING')
	    {
            $domNode->appendChild(new DOMText($text));
	    }
	    
	    elseif ($type=='BIN')
	    {
	     	 $data = '';
	         $file = fopen($text,'rb');
			 while (!feof($file)) {
		         $data .= fread($file, 8192);
			 }
			 fclose($file);
			 $data = base64_encode($data);
			 $domNode->appendChild(new DOMText($data));
	     }
	}
	
	/**
	 * sign是返回内容的校验字串，它是一个32位的MD5校验码，拍拍网返回结果时，会根据返回值和SecretKey来计算这个值。
	 * sign = MD5("&lt;head&gt;...&lt;/body&gt;"+SecretKey )。
	 * 1. &lt;head&gt;标记和&lt;/body&gt;标记间的所有内容，包含每一个空格，换行符，注释内容等都是需要加入MD5运算里的。
	 * 2. &lt;head&gt;前面的空格和&lt;/body&gt;后的空格，换行符不是MD5的目标运算内容，请注意不要误添加上去。
	 * 3. SecretKey是一个字符串内容，它是拍拍网分配给开发者的API调用保密key。
	 * 
	 * @param $xml 装配过后的api的xml的simplexml对象
	 */
	protected function _generateSign($xml)
	{
	    // 拍拍提供的seckey. 配置在main.php配置文件中。
	    // 默认为： 58349ofksu37ujgkg78jdk540p7lwu34
	    $seckey = Yii::app()->params['paipaiApi']['seckey'];
	    /*
	     * 正则表达式匹配从<head>到</body>中的所有字符串。
	     * 结尾匹配模式为：/Uis
	     * 
	     * i －可同时匹配大小写字母
	     * M －将字符串视为多行
	     * S －将字符串视为单行，换行符做普通字符看待，使“.”匹配任何字符
	     * X －模式中的空白忽略不计
	     * U －匹配到最近的字符串
	     * e －将替换的字符串作为表达使用
	     * 
         * 格式：/apple/i匹配“apple”或“Apple”等，忽略大小写。 /i
	     */
	    preg_match("/\<head\>(.*)\<\/body\>/Uis",$xml->asXML(),$match);
	    /*
	     * $match[0] 将包含与整个模式匹配的文本，$match[1] 将包含与第一个捕获的括号中的子模式所匹配的文本，以此类推。 
	     * 这里我们只需要整个模式匹配的文本
	     */
	    // DEBUG 
	    //echo $match[0];
	    return md5($match[0].$seckey);
	}
	
	
}